package com.sig.formes;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import com.sig.opengl.MyGLRenderer;

import android.opengl.GLES20;

public class Segment extends Forme{

	public Point debut;
	public Point fin;


	public Segment(Point debut,Point fin){
		this.debut = debut;
		this.fin = fin;

		creer();
	}

	//segmentIntersection function found on :
	//
	//http://keith-hair.net/blog/2008/08/04/find-intersection-point-of-two-lines-in-as3/
	public Point segmentIntersct(Segment s,boolean as_seg)
	{

		Point ip;
		float a1;
		float a2;
		float b1;
		float b2;
		float c1;
		float c2;

		Point A = debut;
		Point B = fin;
		Point E = s.debut;
		Point F = s.fin;

		a1= B.y-A.y;
		b1= A.x-B.x;
		c1= B.x*A.y - A.x*B.y;
		a2= F.y-E.y;
		b2= E.x-F.x;
		c2= F.x*E.y - E.x*F.y;

		float denom = a1*b2 - a2*b1;
		if(denom == 0){
			return null;
		}
		ip=new Point();
		ip.x=((b1*c2 - b2*c1)/denom);
		ip.y=((a2*c1 - a1*c2)/denom);

		//---------------------------------------------------
		//Do checks to see if intersection to endpoints
		//distance is longer than actual Segments.
		//Return null if it is with any.
		//---------------------------------------------------
		if(as_seg){
			if(distance(ip,B) > distance(A,B)){
				return null;
			}
			if(distance(ip,A) > distance(A,B)){
				return null;
			}  

			if(distance(ip,F) > distance(E,F)){
				return null;
			}
			if(distance(ip,E) > distance(E,F)){
				return null;
			}
		}
		return ip;
	}

	public static double distance(Point fin,Point p2) {
		double dx=fin.x-p2.x;
		double dy=fin.y-p2.y;
		return Math.sqrt(dx*dx+dy*dy);
	}

	public boolean equals(Segment s)
	{
		return ( ( debut == s.debut && fin == s.fin ) || ( debut == s.fin && fin == s.debut ) );
	}

	public Point getCenter()
	{
		return new Point( debut.x + ( fin.x - debut.x )/2, debut.y + ( fin.y - debut.y ) / 2 );
	}

	public double determinant(Point debut,Point fin,Point p2 )
	{
		return ( ( debut.x-fin.x )*( p2.y - fin.y ) ) - ( ( p2.x-fin.x )*( debut.y-fin.y ) );
	}
	public Point midPoint()
	{
		return new Point( ( debut.x + fin.x ) / 2, ( debut.y + fin.y ) / 2 );
	}



	/////////////////////////// OPENGL ///////////////////////




	private final String vertexShaderCode =
			// This matrix member variable provides a hook to manipulate
			// the coordinates of the objects that use this vertex shader
			"uniform mat4 uMVPMatrix;" +

        "attribute vec4 vPosition;" +
        "void main() {" +
        // the matrix must be included as a modifier of gl_Position
        "  gl_Position = vPosition * uMVPMatrix;" +
        "}";

	private final String fragmentShaderCode =
			"precision mediump float;" +
					"uniform vec4 vColor;" +
					"void main() {" +
					"  gl_FragColor = vColor;" +
					"}";

	private FloatBuffer vertexBuffer;
	private int mProgram;
	private int mPositionHandle;
	private int mColorHandle;
	private int mMVPMatrixHandle;

	// number of coordinates per vertex in this array
	static final int COORDS_PER_VERTEX = 3;

	private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

	private void creer(){

		float[] lineCoords = this.getLineCoords();

		// initialize vertex byte buffer for shape coordinates
		ByteBuffer bb = ByteBuffer.allocateDirect(
				// (number of coordinate values * 4 bytes per float)
				lineCoords.length * 4);
		// use the device hardware's native byte order
		bb.order(ByteOrder.nativeOrder());

		// create a floating point buffer from the ByteBuffer
		vertexBuffer = bb.asFloatBuffer();
		// add the coordinates to the FloatBuffer



		vertexBuffer.put(lineCoords);
		// set the buffer to read the first coordinate
		vertexBuffer.position(0);

		// prepare shaders and OpenGL program
		int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
				vertexShaderCode);
		int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
				fragmentShaderCode);

		mProgram = GLES20.glCreateProgram();             // create empty OpenGL Program
		GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
		GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
		GLES20.glLinkProgram(mProgram);                  // create OpenGL program executables

	}

	private float[] getLineCoords(){
		float lineCoords[] = {
				this.debut.x,  this.debut.y,  0.0f,
				this.fin.x, this.fin.y,  0.0f
		};
		return lineCoords;
	}

	public void draw(float[] mvpMatrix) {
		super.draw(mvpMatrix);
		
		// Add program to OpenGL environment
		GLES20.glUseProgram(mProgram);

		// get handle to vertex shader's vPosition member
		mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

		// Enable a handle to the triangle vertices
		GLES20.glEnableVertexAttribArray(mPositionHandle);

		// Prepare the triangle coordinate data
		GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
				GLES20.GL_FLOAT, false,
				vertexStride, vertexBuffer);

		// get handle to fragment shader's vColor member
		mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

		// Set color for drawing the triangle
		GLES20.glUniform4fv(mColorHandle, 1, color, 0);

		// get handle to shape's transformation matrix
		mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
		MyGLRenderer.checkGlError("glGetUniformLocation");

		// Apply the projection and view transformation
		GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
		MyGLRenderer.checkGlError("glUniformMatrix4fv");

		// Draw the line
		int vertexCount = 6 / COORDS_PER_VERTEX;
		GLES20.glDrawArrays(GLES20.GL_LINES, 0, vertexCount);

		// Disable vertex array
		GLES20.glDisableVertexAttribArray(mPositionHandle);
	}
}